home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / vm / vmSeg.c < prev    next >
C/C++ Source or Header  |  1991-05-30  |  61KB  |  2,156 lines

  1. /* vmSeg.c -
  2.  *
  3.  *    This file contains routines that manage the segment table.   It
  4.  *    has routines to allocate, free, expand, and copy segments.  The 
  5.  *    segment table structure and the lists that run through the segment
  6.  *    table are described in vmInt.h.
  7.  *
  8.  * Copyright (C) 1985 Regents of the University of California
  9.  * All rights reserved.
  10.  */
  11.  
  12. #ifndef lint
  13. static char rcsid[] = "$Header: /sprite/src/kernel/vm/RCS/vmSeg.c,v 9.13 91/05/30 15:19:07 kupfer Exp $ SPRITE (Berkeley)";
  14. #endif not lint
  15.  
  16. #include <sprite.h>
  17. #include <vm.h>
  18. #include <vmInt.h>
  19. #include <vmTrace.h>
  20. #include <lock.h>
  21. #include <sync.h>
  22. #include <sys.h>
  23. #include <list.h>
  24. #include <stdlib.h>
  25. #include <fs.h>
  26. #include <status.h>
  27. #include <string.h>
  28. #include <stdio.h>
  29. #include <bstring.h>
  30. #include <assert.h>
  31. #include <machparam.h>
  32.  
  33. Boolean    vm_NoStickySegments = FALSE;        /* TRUE if sticky segments
  34.                          * are disabled. */
  35. Vm_Segment        *vm_SysSegPtr;        /* The system segment. */
  36.  
  37. static    Vm_Segment      *segmentTable;        /* The table of segments. */
  38.  
  39. Vm_SharedSegTable    sharedSegTable;        /* Table of shared segs. */
  40.  
  41. /*
  42.  * Free, inactive and dead segment lists.
  43.  */
  44. static    List_Links      freeSegListHdr;    
  45. static    List_Links      inactiveSegListHdr;
  46. static    List_Links      deadSegListHdr;
  47. #define    freeSegList    (&freeSegListHdr)
  48. #define    inactiveSegList    (&inactiveSegListHdr)
  49. #define    deadSegList    (&deadSegListHdr)
  50.  
  51. /*
  52.  * Condition to wait on when waiting for a code segment to be set up.
  53.  */
  54. Sync_Condition    codeSegCondition;
  55.  
  56. extern    Vm_Segment  **Fs_RetSegPtr();
  57. static void DeleteSeg _ARGS_((register Vm_Segment *segPtr));
  58. static void CleanSegment _ARGS_((register Vm_Segment *segPtr));
  59. static     void        FillSegmentInfo();
  60. static ReturnStatus AddToSeg _ARGS_((register Vm_Segment *segPtr,
  61.     int firstPage, int lastPage, int newNumPages, VmSpace newSpace,
  62.     VmSpace *oldSpacePtr));
  63. void            Fsio_StreamCopy();
  64.  
  65. #ifdef sequent
  66. int    vmNumSegments = 512;
  67. #else /* sequent */
  68. int    vmNumSegments = 256;
  69. #endif /* sequent */
  70.  
  71.  
  72. /*
  73.  * ----------------------------------------------------------------------------
  74.  *
  75.  * VmSegTableAlloc --
  76.  *
  77.  *     Allocate the segment table.
  78.  *
  79.  * Results:
  80.  *     None.
  81.  *
  82.  * Side effects:
  83.  *     Segment table allocated.
  84.  *     
  85.  * ----------------------------------------------------------------------------
  86.  */
  87. void
  88. VmSegTableAlloc()
  89. {
  90.     if (vmMaxMachSegs > 0) {
  91.     if (vmMaxMachSegs < vmNumSegments) {
  92.         vmNumSegments = vmMaxMachSegs;
  93.     }
  94.     }
  95.  
  96.     segmentTable = 
  97.         (Vm_Segment *) Vm_BootAlloc(sizeof(Vm_Segment) * vmNumSegments);
  98.     bzero((Address)segmentTable, vmNumSegments * sizeof(Vm_Segment));
  99.  
  100.     vm_SysSegPtr = &(segmentTable[VM_SYSTEM_SEGMENT]);
  101. }
  102.  
  103.  
  104. /*
  105.  * ----------------------------------------------------------------------------
  106.  *
  107.  * VmSegTableInit --
  108.  *
  109.  *     Initialize the segment table.
  110.  *
  111.  * Results:
  112.  *     None.
  113.  *
  114.  * Side effects:
  115.  *     Segment table initialized plus all segment lists.
  116.  *     
  117.  * ----------------------------------------------------------------------------
  118.  */
  119. void
  120. VmSegTableInit()
  121. {
  122.     int        i;
  123.     Vm_Segment    *segPtr;
  124.  
  125.     /*
  126.      * Initialize the free, inactive and dead segment lists.
  127.      */
  128.     List_Init(freeSegList);
  129.     List_Init(inactiveSegList);
  130.     List_Init(deadSegList);
  131.  
  132.     List_Init((List_Links *)&sharedSegTable);
  133.  
  134.     /*
  135.      * Initialize the segment table.  The kernel gets the system segment and
  136.      * the rest of the segments go onto the segment free list.
  137.      */
  138.     vm_SysSegPtr->refCount = 1;
  139.     vm_SysSegPtr->type = VM_SYSTEM;
  140.     vm_SysSegPtr->offset = (unsigned int)mach_KernStart >> vmPageShift;
  141.     vm_SysSegPtr->flags = 0;
  142.     vm_SysSegPtr->numPages = vmFirstFreePage;
  143.     vm_SysSegPtr->resPages = vmFirstFreePage;
  144.     vm_SysSegPtr->traceTime = 0x7fffffff;
  145.  
  146.     for (i = 0, segPtr = segmentTable; i < vmNumSegments; i++, segPtr++) {
  147.     segPtr->filePtr = (Fs_Stream *)NIL;
  148.     segPtr->swapFilePtr = (Fs_Stream *)NIL;
  149.     segPtr->segNum = i;
  150.     segPtr->cowInfoPtr = (VmCOWInfo *)NIL;
  151.     segPtr->procList = (List_Links *) &(segPtr->procListHdr);
  152.     List_Init(segPtr->procList);
  153.     if (i != VM_SYSTEM_SEGMENT) {
  154.         segPtr->ptPtr = (Vm_PTE *)NIL;
  155.         segPtr->machPtr = (VmMach_SegData *)NIL;
  156.         segPtr->flags = VM_SEG_FREE;
  157.         List_Insert((List_Links *) segPtr, LIST_ATREAR(freeSegList));
  158.     }
  159.     }
  160. }
  161.  
  162. static Vm_Segment *FindCode _ARGS_((Fs_Stream *filePtr, VmProcLink *procLinkPtr, Boolean *usedFilePtr));
  163.  
  164.  
  165. /*
  166.  * ----------------------------------------------------------------------------
  167.  *
  168.  * Vm_FindCode --
  169.  *
  170.  *         Search the segment table for a code segment that has a matching 
  171.  *    filePtr.  Call internal routine to do the work.
  172.  *
  173.  * Results:
  174.  *         A pointer to the matching segment if one is found, NIL if none found. 
  175.  *
  176.  * Side effects:
  177.  *         Memory allocated, *execInfoPtrPtr may be set to point to exec info, and
  178.  *    *userFilePtr is set to TRUE or FALSE depending on whether the filePtr
  179.  *    is used.  If the segment couldn't be found, the file is marked 
  180.  *    to show that we're in the process of setting a segment up.
  181.  *
  182.  * ----------------------------------------------------------------------------
  183.  */
  184. ENTRY Vm_Segment *
  185. Vm_FindCode(filePtr, procPtr, execInfoPtrPtr, usedFilePtr)
  186.     Fs_Stream        *filePtr;    /* Stream for the object file. */
  187.     Proc_ControlBlock    *procPtr;    /* Process for which segment is being
  188.                      * allocated. */
  189.     Vm_ExecInfo        **execInfoPtrPtr;/* Where to return relevant info from
  190.                      * the a.out header. */
  191.     Boolean        *usedFilePtr;    /* TRUE => Had to use the file pointer.
  192.                      * FALSE => didn't have to use it. */
  193. {
  194.     register    Vm_Segment    *segPtr;
  195.     register    VmProcLink    *procLinkPtr;
  196.  
  197.     procLinkPtr = (VmProcLink *) malloc(sizeof(VmProcLink));
  198.     procLinkPtr->procPtr = procPtr;
  199.     segPtr = FindCode(filePtr, procLinkPtr, usedFilePtr);
  200.     if (segPtr == (Vm_Segment *) NIL) {
  201.     free((Address) procLinkPtr);
  202.     } else {
  203.     *execInfoPtrPtr = &segPtr->execInfo;
  204.     }
  205.  
  206.     return(segPtr);
  207. }
  208.  
  209.  
  210. /*
  211.  * ----------------------------------------------------------------------------
  212.  *
  213.  * FindCode --
  214.  *
  215.  *         Search the segment table for a code segment that has a matching 
  216.  *    filePtr.  If one can be found, then increment the reference count
  217.  *    and return a pointer to the segment.  If one can't be found then
  218.  *    mark the file so that subsequent calls to this routine will wait
  219.  *    until this code segment is initialized.
  220.  *
  221.  * Results:
  222.  *         A pointer to the matching segment if one is found, NIL if none found. 
  223.  *
  224.  * Side effects:
  225.  *         If a matching segment is found its reference count is incremented.
  226.  *    *usedFilePtr is set to TRUE or FALSE depending on whether the filePtr
  227.  *    needs to be used for the code segment or not.
  228.  *
  229.  * ----------------------------------------------------------------------------
  230.  */
  231. ENTRY static Vm_Segment *
  232. FindCode(filePtr, procLinkPtr, usedFilePtr)
  233.     Fs_Stream        *filePtr;    /* The unique identifier for this file
  234.                        (if any) */
  235.     VmProcLink        *procLinkPtr;    /* Used to put calling process into 
  236.                      * list of processes using this
  237.                      * segment. */
  238.     Boolean        *usedFilePtr;    /* TRUE => Had to use the file pointer.
  239.                      * FALSE => didn't have to use it. */
  240. {
  241.     register    Vm_Segment    **segPtrPtr;
  242.     register    Vm_Segment    *segPtr;
  243.     ClientData            fileHandle;
  244.  
  245.     LOCK_MONITOR;
  246.  
  247.     *usedFilePtr = FALSE;
  248. again:
  249.     fileHandle = Fs_GetFileHandle(filePtr);
  250.     assert(((unsigned int) fileHandle & WORD_ALIGN_MASK) == 0);
  251.     segPtrPtr = Fs_GetSegPtr(fileHandle);
  252.     if (vm_NoStickySegments || *segPtrPtr == (Vm_Segment *) NIL) {
  253.     /*
  254.      * There is no segment associated with this file.  Set the value to
  255.      * 0 so that we will know that we are about to set up this 
  256.      * association.
  257.      * XXX - if vm_NoStickySegments is TRUE, then we don't check
  258.      * whether there is really a segment associated with the file, 
  259.      * so code segments will apparently never be shared.  Is this 
  260.      * really what we want?  Can it cause a code segment leak?
  261.      */
  262.     *segPtrPtr = (Vm_Segment *) 0;
  263.     segPtr = (Vm_Segment *) NIL;
  264.     } else if (*segPtrPtr == (Vm_Segment *) 0) {
  265.     /*
  266.      * Someone is already trying to allocate this segment.  Wait for
  267.      * them to finish.
  268.      */
  269.     (void)Sync_Wait(&codeSegCondition, FALSE);
  270.     goto again;
  271.     } else {
  272.     segPtr = *segPtrPtr;
  273.     if (segPtr->flags & VM_SEG_INACTIVE) {
  274.         if (segPtr->fileHandle != fileHandle) {
  275.         panic("FindCode: segFileData != fileHandle\n");
  276.         }
  277.         /*
  278.          * The segment is inactive, so delete it from the inactive
  279.          * list.
  280.          */
  281.         List_Remove((List_Links *) segPtr);
  282.         segPtr->flags &= ~VM_SEG_INACTIVE;
  283.         segPtr->filePtr = filePtr;
  284.         *usedFilePtr = TRUE;
  285.     }
  286.     (segPtr->refCount)++;
  287.     /*
  288.      * Put the process into list of processes sharing this segment.
  289.      */
  290.     List_Insert((List_Links *) procLinkPtr, 
  291.             LIST_ATFRONT(segPtr->procList));
  292.     }
  293.  
  294.     UNLOCK_MONITOR;
  295.  
  296.     return(segPtr);
  297. }
  298.  
  299.  
  300. /*
  301.  * ----------------------------------------------------------------------------
  302.  *
  303.  * Vm_InitCode --
  304.  *
  305.  *         Set the association between the file pointer and the segment.  Also
  306.  *    set the exec information info for the segment.  If the segment is
  307.  *    NIL then any processes waiting for the file handle are awakened and
  308.  *    state is cleaned up.
  309.  *
  310.  * Results:
  311.  *         None.
  312.  *
  313.  * Side effects:
  314.  *         Exec info filled in and file pointers segment pointer filled in.
  315.  *
  316.  * ----------------------------------------------------------------------------
  317.  */
  318. ENTRY void
  319. Vm_InitCode(filePtr, segPtr, execInfoPtr)
  320.     Fs_Stream        *filePtr;    /* File for code segment. */
  321.     register Vm_Segment    *segPtr;    /* Segment that is being initialized. */
  322.     Vm_ExecInfo        *execInfoPtr;    /* Information needed to exec this 
  323.                      * object file. */
  324. {
  325.     register    Vm_Segment    **segPtrPtr;
  326.     char            *fileNamePtr;
  327.     int                length;
  328.     ClientData            fileHandle;
  329.  
  330.     LOCK_MONITOR;
  331.  
  332.     fileHandle = Fs_GetFileHandle(filePtr);
  333.     assert(((unsigned int) fileHandle & WORD_ALIGN_MASK) == 0);
  334.     segPtrPtr = Fs_GetSegPtr(fileHandle);
  335.     if (*segPtrPtr != (Vm_Segment *) 0) {
  336.     printf("Warning: Vm_InitCode: Seg ptr = %x\n", *segPtrPtr);
  337.     }
  338.     *segPtrPtr = segPtr;
  339.     if (segPtr == (Vm_Segment *) NIL) {
  340.     /*
  341.      * The caller doesn't want to set up any association between the file
  342.      * and the segment.  In this case cleanup state, i.e., notify any 
  343.      * other processes that might be waiting for the caller (our 
  344.      * process) to finish the association.
  345.      * XXX - Notice that this is the only place where there is a 
  346.      * wakeup on codeSegCondition.  If the caller completes the 
  347.      * association and there are processes waiting, these 
  348.      * processes won't get notified until some other process kills 
  349.      * a partial association.
  350.      */
  351.     Sync_Broadcast(&codeSegCondition);
  352.     } else {
  353.     extern    char    *Fsutil_GetFileName();
  354.     
  355.     segPtr->execInfo = *execInfoPtr;
  356.     segPtr->fileHandle = Fs_GetFileHandle(filePtr);
  357.     fileNamePtr = Fsutil_GetFileName(filePtr);
  358.     if (fileNamePtr != (char *)NIL) {
  359.         length = strlen(fileNamePtr);
  360.         if (length >= VM_OBJ_FILE_NAME_LENGTH) {
  361.         length = VM_OBJ_FILE_NAME_LENGTH - 1;
  362.         }
  363.         (void)strncpy(segPtr->objFileName, fileNamePtr, length);
  364.         segPtr->objFileName[length] = '\0';
  365.     } else {
  366.         segPtr->objFileName[0] = '\0';
  367.     }
  368.     }
  369.  
  370.     UNLOCK_MONITOR;
  371. }
  372.  
  373.  
  374. /*
  375.  *----------------------------------------------------------------------
  376.  *
  377.  * Vm_FileChanged --
  378.  *
  379.  *    This routine is called by the file system when it detects that a
  380.  *    file has been opened for writing.  If the file corresponds to
  381.  *    an unused sticky code segment, the segment will be marked as
  382.  *    deleted.
  383.  *
  384.  * Results:
  385.  *    None.
  386.  *
  387.  * Side effects:
  388.  *    Segment entry may be marked as deleted and put onto the
  389.  *    dead segment list.
  390.  *
  391.  *----------------------------------------------------------------------
  392.  */
  393. ENTRY void
  394. Vm_FileChanged(segPtrPtr)
  395.     Vm_Segment        **segPtrPtr;
  396. {
  397.     register    Vm_Segment    *segPtr;
  398.  
  399.     LOCK_MONITOR;
  400.  
  401.     segPtr = *segPtrPtr;
  402.     if (segPtr != (Vm_Segment *) NIL) {
  403.     if (segPtr->refCount != 0) {
  404.         panic("Vm_FileChanged: In use code seg modified.\n");
  405.     }
  406.     List_Move((List_Links *) segPtr, LIST_ATREAR(deadSegList));
  407.     *segPtrPtr = (Vm_Segment *) NIL;
  408.     segPtr->fileHandle = (ClientData) NIL;
  409.     }
  410.  
  411.     UNLOCK_MONITOR;
  412. }
  413.  
  414. static void GetNewSegment _ARGS_((int type, Fs_Stream *filePtr, int fileAddr, int numPages, int offset, Proc_ControlBlock *procPtr, VmSpace *spacePtr, Vm_Segment **segPtrPtr, Boolean *deletePtr));
  415.  
  416.  
  417. /*
  418.  * ----------------------------------------------------------------------------
  419.  *
  420.  * Vm_SegmentNew --
  421.  *
  422.  *      Allocate a new segment from the segment table.
  423.  *
  424.  * Results:
  425.  *      A pointer to the new segment is returned if a free segment
  426.  *      is available.  If no free segments are available, then NIL is returned.
  427.  *
  428.  * Side effects:
  429.  *      Memory is allocated.
  430.  *
  431.  * ----------------------------------------------------------------------------
  432.  */
  433. Vm_Segment *
  434. Vm_SegmentNew(type, filePtr, fileAddr, numPages, offset, procPtr)
  435.     int            type;        /* The type of segment that this is */
  436.     Fs_Stream        *filePtr;    /* The unique identifier for this file
  437.                        (if any) */
  438.     int            fileAddr;    /* The address where the segments image
  439.                        begins in the object file. */
  440.     int            numPages;    /* Initial size of segment (in pages) */
  441.     int            offset;        /* At which page from the beginning of
  442.                        the VAS that this segment begins */
  443.     Proc_ControlBlock    *procPtr;    /* Process for which the segment is
  444.                        being allocated. */
  445.  
  446. {
  447.     Vm_Segment        *segPtr;
  448.     VmSpace        space;
  449.     Boolean        deleteSeg;
  450.  
  451.     space.procLinkPtr = (VmProcLink *) malloc(sizeof(VmProcLink));
  452.     if (type == VM_CODE) {
  453.     space.ptPtr = (Vm_PTE *) malloc(sizeof(Vm_PTE) * numPages);
  454.     space.ptSize = numPages;
  455.     } else {
  456.     space.ptSize = ((numPages - 1) / vmPageTableInc + 1) * vmPageTableInc;
  457.     space.ptPtr = (Vm_PTE *) malloc(sizeof(Vm_PTE) * space.ptSize);
  458.     }
  459.     segPtr = (Vm_Segment *)NIL;
  460.     GetNewSegment(type, filePtr, fileAddr, numPages, offset,
  461.           procPtr, &space, &segPtr, &deleteSeg);
  462.     if (segPtr != (Vm_Segment *)NIL) {
  463.     if (deleteSeg) {
  464.         /*
  465.          * We have to recycle a code segment before we can allocate a new
  466.          * segment.
  467.          */
  468.         DeleteSeg(segPtr);
  469.         GetNewSegment(type, filePtr, fileAddr, numPages, offset,
  470.               procPtr, &space, &segPtr, &deleteSeg);
  471.     }
  472.     VmMach_SegInit(segPtr);
  473.     } else {
  474.     free((Address)space.procLinkPtr);
  475.     free((Address)space.ptPtr);
  476.     }
  477.     return(segPtr);
  478. }
  479.  
  480.  
  481. /*
  482.  * ----------------------------------------------------------------------------
  483.  *
  484.  * GetNewSegment --
  485.  *
  486.  *         Allocate a new segment from the segment table and return a pointer
  487.  *    to it in *segPtrPtr.  If the new segment corresponds to a dead or
  488.  *    inactive code segment, then *deletePtr will be set to TRUE and the 
  489.  *    caller must cleanup the segment that we returned and call us again 
  490.  *    with *segPtrPtr pointing to the segment that we returned.
  491.  *
  492.  * Results:
  493.  *      None.
  494.  *
  495.  * Side effects:
  496.  *    *segPtrPtr is set to point to a segment in the segment table to
  497.  *    use for the new segment.  If no segments are available then *segPtrPtr
  498.  *    is set to NIL.
  499.  *
  500.  * ----------------------------------------------------------------------------
  501.  */
  502. ENTRY static void
  503. GetNewSegment(type, filePtr, fileAddr, numPages, offset, procPtr,
  504.           spacePtr, segPtrPtr, deletePtr)
  505.     int            type;        /* The type of segment that this is */
  506.     Fs_Stream        *filePtr;    /* Object file stream. */
  507.     int            fileAddr;    /* The address where the segments image
  508.                      * begins in the object file. */
  509.     int            numPages;    /* The number of pages that this segment
  510.                      * initially has. */
  511.     int            offset;        /* At which page from the beginning of
  512.                      * the VAS that this segment begins */
  513.     Proc_ControlBlock    *procPtr;    /* Process for which the segment is
  514.                      *  being allocated. */
  515.     VmSpace        *spacePtr;    /* Memory to be used for this segment.*/    Boolean        *deletePtr;    /* TRUE if have to delete a segment*/
  516.     Vm_Segment        **segPtrPtr;    /* IN/OUT parameter: On input if 
  517.                      * non-nil then this segment should
  518.                      * be used.  On output is the segment
  519.                      * to use. */
  520. {
  521.     register    Vm_Segment    *segPtr;
  522.     register    VmProcLink    *procLinkPtr;
  523.  
  524.     LOCK_MONITOR;
  525.  
  526.     if (*segPtrPtr == (Vm_Segment *)NIL) {
  527.     if (!List_IsEmpty(deadSegList)) {
  528.         /*
  529.          * If there is a dead code segment then use it so that we can free
  530.          * up things.
  531.          */
  532.         segPtr = (Vm_Segment *) List_First(deadSegList);
  533.         *deletePtr = TRUE;
  534.     } else if (!List_IsEmpty(freeSegList)) {
  535.         /*
  536.          * If there is a free segment then use it.
  537.          */
  538.         segPtr = (Vm_Segment *) List_First(freeSegList);
  539.         *deletePtr = FALSE;
  540.     } else if (!List_IsEmpty(inactiveSegList)) {
  541.         /*
  542.          * Inactive segment is available so use it.
  543.          */
  544.         segPtr = (Vm_Segment *) List_First(inactiveSegList);
  545.         *deletePtr = TRUE;
  546.     } else {
  547.         /*
  548.          * No segments are available so return a NIL pointer in *segPtrPtr. 
  549.          */
  550.         *segPtrPtr = (Vm_Segment *)NIL;
  551.         UNLOCK_MONITOR;
  552.         return;
  553.     }
  554.     List_Remove((List_Links *) segPtr);
  555.     *segPtrPtr = segPtr;
  556.     } else {
  557.     segPtr = *segPtrPtr;
  558.     *deletePtr = FALSE;
  559.     }
  560.  
  561.     if (!*deletePtr) {
  562.     /*
  563.      * Initialize the new segment.
  564.      */
  565.     segPtr->fileHandle = (ClientData) NIL;
  566.     segPtr->flags = 0;
  567.     segPtr->refCount = 1;
  568.     segPtr->filePtr = filePtr;
  569.     segPtr->fileAddr = fileAddr;
  570.     segPtr->numPages = numPages;
  571.     segPtr->numCORPages = 0;
  572.     segPtr->numCOWPages = 0;
  573.     segPtr->type = type;
  574.     segPtr->offset = offset;
  575.     segPtr->swapFileName = (char *) NIL;
  576.     segPtr->ptPtr = spacePtr->ptPtr;
  577.     segPtr->ptSize = spacePtr->ptSize;
  578.     bzero((Address)segPtr->ptPtr, segPtr->ptSize * sizeof(Vm_PTE));
  579.     /*
  580.      * If this is a stack segment, the page table grows backwards.  
  581.      * Therefore all of the extra page table that we allocated must be
  582.      * taken off of the offset where the stack was supposed to begin.
  583.      */
  584.     if (segPtr->type == VM_STACK) {
  585.         segPtr->offset = mach_LastUserStackPage - segPtr->ptSize + 1;
  586.     }
  587.     /*
  588.      * Put the process into the list of processes sharing this segment.
  589.      */
  590.     procLinkPtr = spacePtr->procLinkPtr;
  591.     procLinkPtr->procPtr = procPtr;
  592.     List_Insert((List_Links *) procLinkPtr, LIST_ATFRONT(segPtr->procList));
  593.     }
  594.  
  595.     UNLOCK_MONITOR;
  596. }
  597.  
  598.  
  599. /*
  600.  * ----------------------------------------------------------------------------
  601.  *
  602.  * VmSegmentDeleteInt --
  603.  *
  604.  *      This routine will decrement the reference count for the given segment
  605.  *    and return a status to the caller to tell them what action to 
  606.  *    take.
  607.  *
  608.  * Results:
  609.  *    VM_DELETE_SEG -        The segment should be deleted.
  610.  *    VM_CLOSE_OBJ_FILE -    Don't delete the segment, but close the file
  611.  *                containing the code for the segment.
  612.  *    VM_DELETE_NOTHING -    Don't do anything.
  613.  *
  614.  * Side effects:
  615.  *      The segment table for the given segment is modified, the list of 
  616.  *    processes sharing this segment is modified and the inactive list
  617.  *    may be modified.  *objStreamPtrPtr is set to point to the object
  618.  *    file to close if the status is VM_CLOSE_OBJ_FILE.  *procLinkPtrPtr
  619.  *    is set to point to the proc link info struct to free.
  620.  *
  621.  * ----------------------------------------------------------------------------
  622.  */
  623. ENTRY VmDeleteStatus
  624. VmSegmentDeleteInt(segPtr, procPtr, procLinkPtrPtr, objStreamPtrPtr, migFlag)
  625.     register Vm_Segment     *segPtr;    /* Pointer to segment to 
  626.                            delete. */
  627.     register Proc_ControlBlock    *procPtr;    /* Process that was using
  628.                            this segment. */
  629.     VmProcLink            **procLinkPtrPtr;/* Pointer to proc link info
  630.                           * to free. */
  631.     Fs_Stream            **objStreamPtrPtr;/* Pointer to object file
  632.                            * stream to close. */
  633.     Boolean            migFlag;    /* TRUE if segment is being
  634.                            migrated. */
  635. {
  636.     VmProcLink        *procLinkPtr;
  637.  
  638.     LOCK_MONITOR;
  639.  
  640.     segPtr->refCount--;
  641.     
  642.     /*
  643.      * If the segment is not being migrated, then procPtr refers to a process
  644.      * in the list of processes sharing the segment.  Remove this process from
  645.      * the list of processes and make sure that the space is freed.
  646.      */
  647.     if (!migFlag) {
  648.     procLinkPtr = (VmProcLink *)
  649.             List_First((List_Links *) segPtr->procList);
  650.     while (procPtr != procLinkPtr->procPtr) {
  651.         if (List_IsAtEnd(segPtr->procList, (List_Links *) procLinkPtr)) {
  652.         dprintf("Warning: segment %x not on shared seg. list\n",
  653.             (int)segPtr);
  654.         dprintf("Want: %x (%x)\nHave:\n",(int)procLinkPtr->procPtr,
  655.             (int)procLinkPtr->procPtr->processID);
  656.         procLinkPtr = (VmProcLink *)
  657.             List_First((List_Links *) segPtr->procList);
  658.         do {
  659.             dprintf(" %x (%x)\n",(int)(procLinkPtr->procPtr),
  660.                 (int)(procLinkPtr->procPtr->processID));
  661.             procLinkPtr = (VmProcLink *) List_Next((List_Links *) procLinkPtr);
  662.         } while (!List_IsAtEnd(segPtr->procList, (List_Links *) procLinkPtr));
  663.  
  664.         panic("%s%s",
  665.                     "VmSegmentDeleteInt: Could not find segment on shared",
  666.             "segment list.\n");
  667.         }
  668.         procLinkPtr = (VmProcLink *) List_Next((List_Links *) procLinkPtr);
  669.     }
  670.     List_Remove((List_Links *) procLinkPtr);
  671.     *procLinkPtrPtr = procLinkPtr;
  672.     } else {
  673.     *procLinkPtrPtr = (VmProcLink *)NIL;
  674.     }
  675.  
  676.     if (segPtr->refCount > 0) {
  677.     /*
  678.      * The segment is still being used so there is nothing to do.
  679.      */
  680.     UNLOCK_MONITOR;
  681.     return(VM_DELETE_NOTHING);
  682.     }
  683.  
  684.     while (segPtr->ptUserCount > 0 ) {
  685.     dprintf("VmSegmentDeleteInt: ptUserCount = %d\n",segPtr->ptUserCount);
  686.     /*
  687.      * Wait until all users of the page tables of this segment are gone.
  688.      * The only remaining users of a deleted segment would be 
  689.      * prefetch processes.
  690.      */
  691.     (void)Sync_Wait(&segPtr->condition, FALSE);
  692.     dprintf("VmSegmentDeleteInt: done waiting\n");
  693.     }
  694.     if (segPtr->type == VM_SHARED) {
  695.     Vm_SharedSegTable *sharedSeg;
  696.     int found;
  697.     found = 0;
  698.     dprintf("Removing sharedSegTable entry\n");
  699.     LIST_FORALL((List_Links *)&sharedSegTable,(List_Links *)sharedSeg) {
  700.         if (sharedSeg->segPtr == segPtr) {
  701.         List_Remove((List_Links *)sharedSeg);
  702.         found = 1;
  703.         break;
  704.         }
  705.     }
  706.     if (!found) {
  707.         dprintf("Danger! shared segment not found on list!\n");
  708.     } else {
  709.         dprintf("VmSegmentDeleteInt: shared segment removed\n");
  710.     }
  711.     }
  712.     if (!vm_NoStickySegments && segPtr->type == VM_CODE &&
  713.         !(segPtr->flags & (VM_DEBUGGED_SEG | VM_SEG_IO_ERROR))) {
  714.     /* 
  715.      * Put onto the inactive list and tell our caller to close the
  716.      * object file.
  717.      */
  718.     segPtr->flags |= VM_SEG_INACTIVE;
  719.     *objStreamPtrPtr = segPtr->filePtr;
  720.     segPtr->filePtr = (Fs_Stream *) NIL;
  721.     List_Insert((List_Links *) segPtr, LIST_ATREAR(inactiveSegList));
  722.     UNLOCK_MONITOR;
  723.     return(VM_CLOSE_OBJ_FILE);
  724.     } else {
  725.     /*
  726.      * Otherwise tell our caller to delete us.
  727.      */
  728.     UNLOCK_MONITOR;
  729.     return(VM_DELETE_SEG);
  730.     }
  731. }
  732.  
  733.  
  734. /*
  735.  * ----------------------------------------------------------------------------
  736.  *
  737.  * VmPutOnFreeSegList --
  738.  *
  739.  *         Put the given segment onto the end of the segment free list.
  740.  *
  741.  * Results:
  742.  *     None.
  743.  *
  744.  * Side effects:
  745.  *     Segment put onto end of segment free list.
  746.  *
  747.  * ----------------------------------------------------------------------------
  748.  */
  749. ENTRY void
  750. VmPutOnFreeSegList(segPtr)
  751.     register    Vm_Segment    *segPtr;
  752. {
  753.     LOCK_MONITOR;
  754.  
  755.     segPtr->flags = VM_SEG_FREE;
  756.     List_Insert((List_Links *) segPtr, LIST_ATREAR(freeSegList));
  757.  
  758.     UNLOCK_MONITOR;
  759. }
  760.  
  761.  
  762. /*
  763.  * ----------------------------------------------------------------------------
  764.  *
  765.  * Vm_SegmentDelete --
  766.  *
  767.  *         This routine will delete the given segment by calling a monitored
  768.  *    routine to do most of the work.  Since the calls to the memory 
  769.  *    allocator must be done at non-monitor level, if the resources for
  770.  *    this segment must be released then the calls to the machine dependent
  771.  *    routine that uses the memory allocator are done here at non-monitored 
  772.  *    level.
  773.  *
  774.  * Results:
  775.  *     None.
  776.  *
  777.  * Side effects:
  778.  *     None.
  779.  *
  780.  * ----------------------------------------------------------------------------
  781.  */
  782. void
  783. Vm_SegmentDelete(segPtr, procPtr)
  784.     register    Vm_Segment    *segPtr;
  785.     Proc_ControlBlock        *procPtr;
  786. {
  787.     VmDeleteStatus    status;
  788.     VmProcLink        *procLinkPtr;
  789.     Fs_Stream        *objStreamPtr;
  790.  
  791.     status = VmSegmentDeleteInt(segPtr, procPtr, &procLinkPtr, &objStreamPtr,
  792.                 FALSE);
  793.     if (status == VM_DELETE_SEG) {
  794.     DeleteSeg(segPtr);
  795.     VmPutOnFreeSegList(segPtr);
  796.     } else if (status == VM_CLOSE_OBJ_FILE) {
  797.     (void)Fs_Close(objStreamPtr);
  798.     }
  799.  
  800.     free((Address)procLinkPtr);
  801. }
  802.  
  803.  
  804. /*
  805.  * ----------------------------------------------------------------------------
  806.  *
  807.  * DeleteSeg --
  808.  *
  809.  *    Actually delete a segment.  This includes freeing all memory 
  810.  *    resources for the segment and calling machine dependent cleanup.
  811.  *
  812.  * Results:
  813.  *         None.
  814.  *
  815.  * Side effects:
  816.  *         Allocated resources freed in the give segment and the pointers
  817.  *    in the segment are set to NIL.
  818.  *
  819.  * ----------------------------------------------------------------------------
  820.  */
  821. static void
  822. DeleteSeg(segPtr)
  823.     register    Vm_Segment    *segPtr;
  824. {
  825.     if (vm_CanCOW) {
  826.     VmCOWDeleteFromSeg(segPtr, -1, -1);
  827.     }
  828.     CleanSegment(segPtr);
  829.     VmMach_SegDelete(segPtr);
  830.  
  831.     free((Address)segPtr->ptPtr);
  832.     segPtr->ptPtr = (Vm_PTE *)NIL;
  833.     if (segPtr->filePtr != (Fs_Stream *)NIL) {
  834.     (void)Fs_Close(segPtr->filePtr);
  835.     segPtr->filePtr = (Fs_Stream *)NIL;
  836.     }
  837.     if (segPtr->flags & VM_SWAP_FILE_OPENED) {
  838.     VmSwapFileRemove(segPtr->swapFilePtr, segPtr->swapFileName);
  839.     segPtr->swapFilePtr = (Fs_Stream *)NIL;
  840.     segPtr->swapFileName = (char *)NIL;
  841.     }
  842. }
  843.  
  844.  
  845. /*
  846.  * ----------------------------------------------------------------------------
  847.  *
  848.  * CleanSegment --
  849.  *
  850.  *    Do monitor level state cleanup for a deleted segment.
  851.  *
  852.  * Results:
  853.  *         None.
  854.  *
  855.  * Side effects:
  856.  *         All pages allocated to the segment are freed.
  857.  *     
  858.  * ----------------------------------------------------------------------------
  859.  */
  860. ENTRY static void
  861. CleanSegment(segPtr)
  862.     register Vm_Segment *segPtr;    /* Pointer to the segment to be 
  863.                      * cleaned */
  864. {
  865.     register    Vm_PTE    *ptePtr;
  866.     register    int        i;
  867.     Vm_VirtAddr        virtAddr;
  868.     Vm_Segment        **segPtrPtr;
  869.  
  870.     LOCK_MONITOR;
  871.  
  872.     segPtr->flags |= VM_SEG_DEAD;
  873.  
  874.     virtAddr.segPtr = segPtr;
  875.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  876.     if (segPtr->type == VM_STACK) {
  877.     virtAddr.page = mach_LastUserStackPage - segPtr->numPages + 1;
  878.     } else {
  879.     virtAddr.page = segPtr->offset;
  880.     }
  881.     ptePtr = VmGetPTEPtr(segPtr, virtAddr.page);
  882.  
  883.     if (segPtr->fileHandle != (ClientData) NIL) {
  884.     /*
  885.      * This segment is associated with a file.  Find out which one and
  886.      * break the connection.
  887.      */
  888.     segPtrPtr = Fs_GetSegPtr(segPtr->fileHandle);
  889.     *segPtrPtr = (Vm_Segment *) NIL;
  890.     segPtr->fileHandle = (ClientData) NIL;
  891.     }
  892.  
  893.     /*
  894.      * Free all pages that this segment has in real memory.
  895.      */
  896.     for (i = segPtr->numPages; 
  897.          i > 0; 
  898.      i--, VmIncPTEPtr(ptePtr, 1), virtAddr.page++) {
  899.     if (*ptePtr & VM_PHYS_RES_BIT) {
  900.         VmMach_PageInvalidate(&virtAddr, Vm_GetPageFrame(*ptePtr),
  901.                   TRUE);
  902.         VmPageFreeInt(Vm_GetPageFrame(*ptePtr));
  903.     }
  904.     }
  905.  
  906.     segPtr->resPages = 0;
  907.  
  908.     UNLOCK_MONITOR;
  909. }
  910.  
  911. static Boolean StartDelete _ARGS_((Vm_Segment *segPtr, int firstPage, int *lastPagePtr));
  912. static ReturnStatus EndDelete _ARGS_((register Vm_Segment *segPtr, int firstPage, int lastPage));
  913.  
  914.  
  915. /*
  916.  *----------------------------------------------------------------------
  917.  *
  918.  * Vm_DeleteFromSeg --
  919.  *
  920.  *    Take the range of virtual page numbers for the given heap segment,
  921.  *    invalidate them, make them unaccessible and make the segment
  922.  *    smaller if necessary.
  923.  *    
  924.  * Results:
  925.  *    None.
  926.  *
  927.  * Side effects:
  928.  *    None.
  929.  *
  930.  *----------------------------------------------------------------------
  931.  */
  932. ReturnStatus
  933. Vm_DeleteFromSeg(segPtr, firstPage, lastPage)
  934.     Vm_Segment     *segPtr;    /* The segment whose pages are being
  935.                    invalidated. */
  936.     int        firstPage;    /* The first page to invalidate */
  937.     int        lastPage;    /* The second page to invalidate. */
  938. {
  939.     /*
  940.      * The deletion of virtual pages from the segment is done in two
  941.      * phases.  First the copy-on-write dependencies are cleaned up and
  942.      * then the rest of the pages are cleaned up.  This requires some
  943.      * synchronization.  The problem is that during and after cleaning up
  944.      * the copy-on-write dependencies, page faults and copy-on-write forks
  945.      * in the segment must be prevented since cleanup is done at non-monitor
  946.      * level.  This is done by using the VM_PT_EXCL_ACC flag.  When this flag 
  947.      * is set page faults and forks are blocked because they are unable
  948.      * to get access to the page tables until the exclusive access flag
  949.      * is cleared.  This flag is set by StartDelete and cleared by EndDelete. 
  950.      * The flag is looked at by VmVirtAddrParse (the routine that is called 
  951.      * before any page fault can occur on the segment) and by IncPTUserCount
  952.      * (the routine that is called when a segment is duplicated for a fork).
  953.      */
  954.     if (!StartDelete(segPtr, firstPage, &lastPage)) {
  955.     return(SUCCESS);
  956.     }
  957.     /*
  958.      * Rid the segment of all copy-on-write dependencies.
  959.      */
  960.     VmCOWDeleteFromSeg(segPtr, firstPage, lastPage);
  961.  
  962.     return(EndDelete(segPtr, firstPage, lastPage));
  963. }
  964.  
  965.  
  966. /*
  967.  *----------------------------------------------------------------------
  968.  *
  969.  * StartDelete --
  970.  *
  971.  *    Set things up to delete pages from a segment.  This involves grabbing
  972.  *    exclusive access to the page tables for the segment.
  973.  *
  974.  * Results:
  975.  *    FALSE if there is nothing to delete from this segment.
  976.  *
  977.  * Side effects:
  978.  *    Page table user count incremented and exclusive access grabbed on
  979.  *    the page tables.
  980.  *
  981.  *----------------------------------------------------------------------
  982.  */
  983. ENTRY static Boolean
  984. StartDelete(segPtr, firstPage, lastPagePtr)
  985.     Vm_Segment    *segPtr;
  986.     int        firstPage;
  987.     int        *lastPagePtr;
  988. {
  989.     Boolean    retVal;
  990.     int        lastSegPage;
  991.  
  992.     LOCK_MONITOR;
  993.  
  994.     while (segPtr->ptUserCount > 0) {
  995.     (void) Sync_Wait(&segPtr->condition, FALSE);
  996.     }
  997.  
  998.     /*
  999.      * If the beginning address falls past the end of the heap segment
  1000.      * then there is nothing to do so return.  If the ending address 
  1001.      * falls past the end of the heap segment then it must be rounded
  1002.      * down and the segment made smaller.
  1003.      */
  1004.     lastSegPage = segPtr->offset + segPtr->numPages - 1;
  1005.     if (firstPage <= lastSegPage) {
  1006.     if (*lastPagePtr >= lastSegPage) {
  1007.         *lastPagePtr = lastSegPage;
  1008.     }
  1009.     /*
  1010.      * Make sure that no one expands or shrinks the segment while 
  1011.      * we are expanding it.
  1012.      */
  1013.     segPtr->ptUserCount = 1;
  1014.     segPtr->flags |= VM_PT_EXCL_ACC;
  1015.     retVal = TRUE;
  1016.     } else {
  1017.     retVal = FALSE;
  1018.     }
  1019.     UNLOCK_MONITOR;
  1020.     return(retVal);
  1021. }
  1022.  
  1023.  
  1024. /*
  1025.  *----------------------------------------------------------------------
  1026.  *
  1027.  * EndDelete --
  1028.  *
  1029.  *    Clean up after a delete has finished.
  1030.  *
  1031.  * Results:
  1032.  *    None.
  1033.  *
  1034.  * Side effects:
  1035.  *    Page table user count decremented, exclusive access on the page tables
  1036.  *    is released and the segment size may be shrunk.
  1037.  *
  1038.  *----------------------------------------------------------------------
  1039.  */
  1040. ENTRY static ReturnStatus
  1041. EndDelete(segPtr, firstPage, lastPage)
  1042.     register    Vm_Segment    *segPtr;
  1043.     int                firstPage;
  1044.     int                lastPage;
  1045. {
  1046.     register    Vm_PTE    *ptePtr;
  1047.     Vm_VirtAddr        virtAddr;
  1048.     unsigned    int    pfNum;
  1049.     ReturnStatus    status = SUCCESS;
  1050.  
  1051.     LOCK_MONITOR;
  1052.  
  1053.     if (lastPage == segPtr->offset + segPtr->numPages - 1) {
  1054.     segPtr->numPages -= lastPage - firstPage + 1;
  1055.     }
  1056.  
  1057.     /*
  1058.      * Free up any resident pages.
  1059.      */
  1060.     virtAddr.segPtr = segPtr;
  1061.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  1062.     for (virtAddr.page = firstPage, ptePtr = VmGetPTEPtr(segPtr, firstPage);
  1063.      virtAddr.page <= lastPage;
  1064.      virtAddr.page++, VmIncPTEPtr(ptePtr, 1)) {
  1065.     if (*ptePtr & VM_PHYS_RES_BIT) {
  1066.         if (VmPagePinned(ptePtr)) {
  1067.         status = FAILURE;
  1068.         goto exit;
  1069.         }
  1070.         VmMach_PageInvalidate(&virtAddr, Vm_GetPageFrame(*ptePtr), FALSE);
  1071.         segPtr->resPages--;
  1072.         pfNum = Vm_GetPageFrame(*ptePtr);
  1073.         *ptePtr = 0;
  1074.         VmPageFreeInt(pfNum);
  1075.     }
  1076.     *ptePtr = 0;
  1077.     }
  1078.  
  1079. exit:
  1080.     /*
  1081.      * Release exclusive access.
  1082.      */
  1083.     segPtr->ptUserCount = 0;
  1084.     segPtr->flags &= ~VM_PT_EXCL_ACC;
  1085.     Sync_Broadcast(&segPtr->condition);
  1086.  
  1087.     UNLOCK_MONITOR;
  1088.     return(status);
  1089. }
  1090.  
  1091.  
  1092. /*
  1093.  * ----------------------------------------------------------------------------
  1094.  *
  1095.  * VmDecPTUserCount --
  1096.  *
  1097.  *         Decrement the number of users of the page tables for this segment.
  1098.  *    If the count goes to zero then wake up anyone waiting on it.
  1099.  *
  1100.  * Results:
  1101.  *     None.
  1102.  *
  1103.  * Side effects:
  1104.  *     Count of users of page table decremented.
  1105.  *     
  1106.  * ----------------------------------------------------------------------------
  1107.  */
  1108. ENTRY void
  1109. VmDecPTUserCount(segPtr)
  1110.     register    Vm_Segment        *segPtr;
  1111. {
  1112.     LOCK_MONITOR;
  1113.  
  1114.     segPtr->ptUserCount--;
  1115.     if (segPtr->ptUserCount == 0) {
  1116.     Sync_Broadcast(&segPtr->condition);
  1117.     }
  1118.  
  1119.     UNLOCK_MONITOR;
  1120. }
  1121.  
  1122. static void StartExpansion _ARGS_((Vm_Segment *segPtr));
  1123. static void EndExpansion _ARGS_((Vm_Segment *segPtr));
  1124. static void AllocMoreSpace _ARGS_((register Vm_Segment *segPtr, int newNumPages, register VmSpace *spacePtr));
  1125.  
  1126.  
  1127. /*
  1128.  *----------------------------------------------------------------------
  1129.  *
  1130.  * VmAddToSeg --
  1131.  *
  1132.  *    Make all pages between firstPage and lastPage be in the segment's 
  1133.  *    virtual address space.
  1134.  *
  1135.  * Results:
  1136.  *    An error if for some reason the range of virtual pages cannot be
  1137.  *    put into the segment's VAS.  Otherwise SUCCESS is returned.
  1138.  *
  1139.  * Side effects:
  1140.  *    None.
  1141.  *
  1142.  *----------------------------------------------------------------------
  1143.  */
  1144. ReturnStatus
  1145. VmAddToSeg(segPtr, firstPage, lastPage)
  1146.     register Vm_Segment *segPtr;    /* The segment whose VAS is to be
  1147.                      * modified. */
  1148.     int                       firstPage;     /* The lowest page to put into the 
  1149.                      * VAS. */
  1150.     int                       lastPage;     /* The highest page to put into the 
  1151.                      * VAS. */
  1152. {
  1153.     VmSpace    newSpace;
  1154.     VmSpace    oldSpace;
  1155.     int        retValue;
  1156.     int        newNumPages;
  1157.  
  1158.     /*
  1159.      * The only segments that can be expanded are the stack, heap, and
  1160.      * shared segments.
  1161.      */
  1162.     if (segPtr->type == VM_CODE || segPtr->type == VM_SYSTEM) {
  1163.     return(VM_WRONG_SEG_TYPE);
  1164.     }
  1165.  
  1166.     StartExpansion(segPtr);
  1167.  
  1168.     if (segPtr->type == VM_STACK) {
  1169.     newNumPages = mach_LastUserStackPage - firstPage + 1;
  1170.     AllocMoreSpace(segPtr, newNumPages, &newSpace);
  1171.     } else {
  1172.     newNumPages = lastPage - segPtr->offset + 1;
  1173.     AllocMoreSpace(segPtr, newNumPages, &newSpace);
  1174.     }
  1175.  
  1176.     retValue = AddToSeg(segPtr, firstPage, lastPage, newNumPages, 
  1177.             newSpace, &oldSpace);
  1178.     if (oldSpace.spaceToFree && oldSpace.ptPtr != (Vm_PTE *)NIL) {
  1179.     free((Address)oldSpace.ptPtr);
  1180.     }
  1181.     VmMach_SegExpand(segPtr, firstPage, lastPage);
  1182.  
  1183.     EndExpansion(segPtr);
  1184.  
  1185.     return(retValue);
  1186. }
  1187.  
  1188.  
  1189. /*
  1190.  *----------------------------------------------------------------------
  1191.  *
  1192.  * StartExpansion --
  1193.  *
  1194.  *    Grab exclusive access to the page tables.
  1195.  *
  1196.  * Results:
  1197.  *    None.
  1198.  *
  1199.  * Side effects:
  1200.  *    Page table user count incremented and VM_PT_EXCL_ACC flag set.
  1201.  *
  1202.  *----------------------------------------------------------------------
  1203.  */
  1204. ENTRY static void
  1205. StartExpansion(segPtr)
  1206.     Vm_Segment    *segPtr;
  1207. {
  1208.     LOCK_MONITOR;
  1209.  
  1210.     while (segPtr->ptUserCount > 0) {
  1211.     (void)Sync_Wait(&segPtr->condition, FALSE);
  1212.     }
  1213.     segPtr->flags |= VM_PT_EXCL_ACC;
  1214.     segPtr->ptUserCount++;
  1215.  
  1216.     UNLOCK_MONITOR;
  1217. }
  1218.  
  1219.  
  1220.  
  1221. /*
  1222.  *----------------------------------------------------------------------
  1223.  *
  1224.  * EndExpansion --
  1225.  *
  1226.  *    Release the lock on the page tables that prevents expansions and
  1227.  *    deletions from the segment.
  1228.  *
  1229.  * Results:
  1230.  *    None.
  1231.  *
  1232.  * Side effects:
  1233.  *    Page table user count decremented and VM_PT_EXCL_ACC flag cleared.
  1234.  *
  1235.  *----------------------------------------------------------------------
  1236.  */
  1237. ENTRY static void
  1238. EndExpansion(segPtr)
  1239.     Vm_Segment    *segPtr;
  1240. {
  1241.     LOCK_MONITOR;
  1242.  
  1243.     segPtr->flags &= ~VM_PT_EXCL_ACC;
  1244.     segPtr->ptUserCount--;
  1245.     Sync_Broadcast(&segPtr->condition);
  1246.  
  1247.     UNLOCK_MONITOR;
  1248. }
  1249.  
  1250.  
  1251. /*
  1252.  *----------------------------------------------------------------------
  1253.  *
  1254.  * AllocMoreSpace --
  1255.  *
  1256.  *    Allocate more space for the page tables for this segment that is
  1257.  *    growing.  endVirtPage is the highest accessible page if it is
  1258.  *    a heap segment and the lowest accessible page if it is a stack
  1259.  *     segment.
  1260.  *
  1261.  * Results:
  1262.  *    None.
  1263.  *
  1264.  * Side effects:
  1265.  *    The page table might be expanded.
  1266.  *
  1267.  *----------------------------------------------------------------------
  1268.  */
  1269. static void
  1270. AllocMoreSpace(segPtr, newNumPages, spacePtr)
  1271.     register    Vm_Segment    *segPtr;
  1272.     int                newNumPages;
  1273.     register    VmSpace        *spacePtr;
  1274. {
  1275.     /*
  1276.      * Find out the new size of the page table.
  1277.      */
  1278.     spacePtr->ptSize = ((newNumPages - 1)/vmPageTableInc + 1) * vmPageTableInc;
  1279.     /*
  1280.      * Since page tables never get smaller we can see if the page table
  1281.      * is already big enough.
  1282.      */
  1283.     if (spacePtr->ptSize <= segPtr->ptSize) {
  1284.     spacePtr->ptPtr = (Vm_PTE *) NIL;
  1285.     } else {
  1286.     spacePtr->ptPtr = (Vm_PTE *)malloc(sizeof(Vm_PTE) * spacePtr->ptSize);
  1287.     }
  1288. }
  1289.  
  1290.  
  1291. /*
  1292.  *----------------------------------------------------------------------
  1293.  *
  1294.  * AddToSeg --
  1295.  *
  1296.  *    Make all pages between firstPage and lastPage be in the segments 
  1297.  *    virtual address space.
  1298.  *
  1299.  * Results:
  1300.  *    An error if for some reason the range of virtual pages cannot be
  1301.  *    put into the segment's VAS.  Otherwise SUCCESS is returned.
  1302.  *
  1303.  * Side effects:
  1304.  *    None.
  1305.  *
  1306.  *----------------------------------------------------------------------
  1307.  */
  1308. ENTRY static ReturnStatus 
  1309. AddToSeg(segPtr, firstPage, lastPage, newNumPages, newSpace, oldSpacePtr)
  1310.     register    Vm_Segment    *segPtr;    /* The segment to add the
  1311.                          * virtual pages to. */
  1312.     int                firstPage;    /* The lowest page to put
  1313.                          * into the VAS. */
  1314.     int                lastPage;    /* The highest page to put
  1315.                          * into the VAS. */
  1316.     int                newNumPages;    /* The new number of pages
  1317.                          * that will be in the
  1318.                          * segment. */
  1319.     VmSpace            newSpace;    /* Pointer to new page table
  1320.                          * if the segment has to
  1321.                          * be expanded. */
  1322.     VmSpace            *oldSpacePtr;    /* Place to return pointer
  1323.                          * to space to free. */
  1324. {
  1325.     int                copySize;
  1326.     int                byteOffset;
  1327.     register    VmProcLink    *procLinkPtr;
  1328.     register    Vm_Segment    *otherSegPtr;
  1329.  
  1330.     LOCK_MONITOR;
  1331.  
  1332.     *oldSpacePtr = newSpace;
  1333.     oldSpacePtr->spaceToFree = TRUE;
  1334.  
  1335.     copySize = segPtr->ptSize * sizeof(Vm_PTE);
  1336.     if (newNumPages > segPtr->ptSize) {
  1337.     if (segPtr->type == VM_HEAP) {
  1338.         /*
  1339.          * Go through all proc table entries for all processes sharing
  1340.          * this segment and make sure that no stack segment is too large.
  1341.          */
  1342.         LIST_FORALL(segPtr->procList, (List_Links *) procLinkPtr) {
  1343.         otherSegPtr = 
  1344.             procLinkPtr->procPtr->vmPtr->segPtrArray[VM_STACK];
  1345.         if (newSpace.ptSize + segPtr->offset >= otherSegPtr->offset) {
  1346.             UNLOCK_MONITOR;
  1347.             return(VM_SEG_TOO_LARGE);
  1348.         }
  1349.         }
  1350.         /*
  1351.          * This isn't a stack segment so just copy the page table 
  1352.          * into the lower part, and zero the rest.
  1353.          */
  1354.         bcopy((Address) segPtr->ptPtr, (Address) newSpace.ptPtr, copySize);
  1355.         bzero((Address) ((int) (newSpace.ptPtr) + copySize),
  1356.             (newSpace.ptSize - segPtr->ptSize)  * sizeof(Vm_PTE));
  1357.     } else if (segPtr->type == VM_STACK) {
  1358.         /*
  1359.          * Make sure that the heap segment isn't too big.  If it is then 
  1360.          * abort.
  1361.          */
  1362.         otherSegPtr = Proc_GetCurrentProc()->vmPtr->segPtrArray[VM_HEAP];
  1363.         if (otherSegPtr->offset + otherSegPtr->ptSize >= 
  1364.         mach_LastUserStackPage - newSpace.ptSize + 1) {
  1365.         UNLOCK_MONITOR;
  1366.         return(VM_SEG_TOO_LARGE);
  1367.         }
  1368.         /*
  1369.          * In this case the current page table has to be copied to the 
  1370.          * high part of the new page table and the lower part has to be 
  1371.          * zeroed.  Also the offset has to be adjusted to compensate for 
  1372.          * making the page table bigger than requested.
  1373.          */
  1374.         byteOffset = (newSpace.ptSize - segPtr->ptSize) * sizeof(Vm_PTE);
  1375.         bcopy((Address) segPtr->ptPtr,
  1376.             (Address) ((int) (newSpace.ptPtr) + byteOffset), copySize);
  1377.         bzero((Address) newSpace.ptPtr, byteOffset);
  1378.         segPtr->offset -= newSpace.ptSize - segPtr->ptSize;
  1379.     }
  1380.     oldSpacePtr->ptPtr = segPtr->ptPtr;
  1381.     segPtr->ptPtr = newSpace.ptPtr;
  1382.     segPtr->ptSize = newSpace.ptSize;
  1383.     }
  1384.     if (newNumPages > segPtr->numPages) {
  1385.     segPtr->numPages = newNumPages;
  1386.     }
  1387.     /* 
  1388.      * Make all pages between firstPage and lastPage zero-fill-on-demand
  1389.      * members of the segment's virtual address space.
  1390.      */
  1391.     VmValidatePagesInt(segPtr, firstPage, lastPage, TRUE, FALSE);
  1392.  
  1393.     UNLOCK_MONITOR;
  1394.  
  1395.     return(SUCCESS);
  1396. }
  1397.  
  1398. static void IncPTUserCount _ARGS_((register Vm_Segment *segPtr));
  1399. static void CopyInfo _ARGS_((register Vm_Segment *srcSegPtr, register Vm_Segment *destSegPtr, register Vm_PTE **srcPTEPtrPtr, register Vm_PTE **destPTEPtrPtr, Vm_VirtAddr *srcVirtAddrPtr, Vm_VirtAddr *destVirtAddrPtr));
  1400. ENTRY static Boolean CopyPage _ARGS_((Vm_Segment *srcSegPtr,
  1401.     register Vm_PTE *srcPTEPtr, register Vm_PTE *destPTEPtr));
  1402.  
  1403.  
  1404. /*
  1405.  *----------------------------------------------------------------------
  1406.  *
  1407.  * Vm_SegmentDup --
  1408.  *
  1409.  *    Duplicate the given segment and return a pointer to the copy in
  1410.  *    *destSegPtrPtr.  If the segment that is being copied is shared by 
  1411.  *    other processes then the segment could be being modified while it is 
  1412.  *    being copied.  Hence there is no guarantee that the segment will
  1413.  *    be in the same state after it is duplicated as it was when this
  1414.  *    routine was called.
  1415.  *
  1416.  * Results:
  1417.  *    VM_SWAP_ERROR if swap space could not be duplicated or VM_NO_SEGMENTS
  1418.  *    if are out of segments.  Otherwise return SUCCESS.
  1419.  *
  1420.  * Side effects:
  1421.  *    New segment allocated, initialized and copied into.
  1422.  *
  1423.  *----------------------------------------------------------------------
  1424.  */
  1425. ReturnStatus
  1426. Vm_SegmentDup(srcSegPtr, procPtr, destSegPtrPtr)
  1427.     register Vm_Segment *srcSegPtr;    /* Pointer to the segment to be 
  1428.                      * duplicate. */
  1429.     Proc_ControlBlock   *procPtr;     /* Pointer to the process for which the 
  1430.                      * segment is being duplicated. */
  1431.     Vm_Segment        **destSegPtrPtr;/* Place to return pointer to new
  1432.                      * segment. */
  1433. {
  1434.     register    Vm_Segment    *destSegPtr;
  1435.     ReturnStatus        status;
  1436.     register    Vm_PTE        *srcPTEPtr;
  1437.     register    Vm_PTE        *destPTEPtr;
  1438.     Vm_PTE            *tSrcPTEPtr;
  1439.     Vm_PTE            *tDestPTEPtr;
  1440.     Vm_VirtAddr            srcVirtAddr;
  1441.     Vm_VirtAddr            destVirtAddr;
  1442.     int                i;
  1443. #ifndef sequent    
  1444.     Address            srcAddr = (Address) NIL;
  1445.     Address            destAddr = (Address)NIL;
  1446. #endif    
  1447.     Fs_Stream            *newFilePtr;
  1448.  
  1449.     if (srcSegPtr->type == VM_HEAP) {
  1450.     Fsio_StreamCopy(srcSegPtr->filePtr, &newFilePtr);
  1451.     } else {
  1452.     newFilePtr = (Fs_Stream *) NIL;
  1453.     }
  1454.     /*
  1455.      * Prevent the source segment from being expanded.
  1456.      */
  1457.     IncPTUserCount(srcSegPtr);
  1458.  
  1459.     /*
  1460.      * Allocate the segment that we are copying to.
  1461.      */
  1462.     destSegPtr = Vm_SegmentNew(srcSegPtr->type, newFilePtr,
  1463.                    srcSegPtr->fileAddr, srcSegPtr->numPages, 
  1464.                    srcSegPtr->offset, procPtr);
  1465.     if (destSegPtr == (Vm_Segment *) NIL) {
  1466.     VmDecPTUserCount(srcSegPtr);
  1467.     if (srcSegPtr->type == VM_HEAP) {
  1468.         (void)Fs_Close(newFilePtr);
  1469.     }
  1470.     *destSegPtrPtr = (Vm_Segment *) NIL;
  1471.     return(VM_NO_SEGMENTS);
  1472.     }
  1473.     destSegPtr->flags |= VM_SEG_CREATE_TRACED;
  1474.  
  1475.     if (vm_CanCOW) {
  1476.     if (VmSegCanCOW(srcSegPtr)) {
  1477.         /*
  1478.          * We are allowed to make this segment copy-on-write so do it.
  1479.          */
  1480.         if (vm_Tracing) {
  1481.         Vm_TraceSegCreate    segCreate;
  1482.  
  1483.         segCreate.segNum = destSegPtr->segNum;
  1484.         segCreate.parSegNum = srcSegPtr->segNum;
  1485.         segCreate.segType = destSegPtr->type;
  1486.         segCreate.cor = TRUE;
  1487.         VmStoreTraceRec(VM_TRACE_SEG_CREATE_REC, sizeof(segCreate),
  1488.                 (Address)&segCreate, TRUE);
  1489.         }
  1490.         /*
  1491.          * We are allowing copy-on-write.  Make a copy-on-ref image of the
  1492.          * src segment in the dest segment.
  1493.          */
  1494.         VmSegFork(srcSegPtr, destSegPtr);
  1495.         VmDecPTUserCount(srcSegPtr);
  1496.         *destSegPtrPtr = destSegPtr;
  1497.  
  1498.         VmSegCOWDone(srcSegPtr, FALSE);
  1499.  
  1500.         return(SUCCESS);
  1501.     }
  1502.     }
  1503.     if (vm_Tracing) {
  1504.     Vm_TraceSegCreate    segCreate;
  1505.  
  1506.     segCreate.segNum = destSegPtr->segNum;
  1507.     segCreate.parSegNum = srcSegPtr->segNum;
  1508.     segCreate.segType = destSegPtr->type;
  1509.     segCreate.cor = FALSE;
  1510.     VmStoreTraceRec(VM_TRACE_SEG_CREATE_REC, sizeof(segCreate),
  1511.             (Address)&segCreate, TRUE);
  1512.     }
  1513.  
  1514.     /*
  1515.      * No copy-on-write.  Do a full fledged copy of the source segment to
  1516.      * the dest segment.
  1517.      */
  1518.     CopyInfo(srcSegPtr, destSegPtr, &tSrcPTEPtr, &tDestPTEPtr, &srcVirtAddr,
  1519.          &destVirtAddr);
  1520.  
  1521.     /*
  1522.      * Copy over memory.
  1523.      */
  1524.     for (i = 0, srcPTEPtr = tSrcPTEPtr, destPTEPtr = tDestPTEPtr; 
  1525.      i < destSegPtr->numPages; 
  1526.      i++, VmIncPTEPtr(srcPTEPtr, 1), VmIncPTEPtr(destPTEPtr, 1), 
  1527.         destVirtAddr.page++, srcVirtAddr.page++) {
  1528.     if (CopyPage(srcSegPtr, srcPTEPtr, destPTEPtr)) {
  1529.         *destPTEPtr |= VM_REFERENCED_BIT | VM_MODIFIED_BIT |
  1530.                        VmPageAllocate(&destVirtAddr, VM_CAN_BLOCK);
  1531.         destSegPtr->resPages++;
  1532. #ifndef sequent
  1533.         if (srcAddr == (Address) NIL) {
  1534.         VmMach_FlushPage(&srcVirtAddr, FALSE);
  1535.         srcAddr = VmMapPage(Vm_GetPageFrame(*srcPTEPtr));
  1536.         destAddr = VmMapPage(Vm_GetPageFrame(*destPTEPtr));
  1537.         } else {
  1538.         VmMach_FlushPage(&srcVirtAddr, FALSE);
  1539.         VmRemapPage(srcAddr, Vm_GetPageFrame(*srcPTEPtr));
  1540.         VmRemapPage(destAddr, Vm_GetPageFrame(*destPTEPtr));
  1541.         }
  1542.         bcopy(srcAddr, destAddr, vm_PageSize);
  1543. #else    /* sequent */
  1544.         VmMachCopyPage(Vm_GetPageFrame(*srcPTEPtr),
  1545.                     Vm_GetPageFrame(*destPTEPtr));
  1546. #endif    /* sequent */
  1547.         VmUnlockPage(Vm_GetPageFrame(*srcPTEPtr));
  1548.         VmUnlockPage(Vm_GetPageFrame(*destPTEPtr));
  1549.     }
  1550.     }
  1551. #ifndef sequent    
  1552.     /*
  1553.      * Unmap any mapped pages.
  1554.      */
  1555.     if (srcAddr != (Address) NIL) {
  1556.         VmUnmapPage(srcAddr);
  1557.         VmUnmapPage(destAddr);
  1558.     }
  1559. #endif
  1560.     /*
  1561.      * Copy over swap space resources.
  1562.      */
  1563.     status = VmCopySwapSpace(srcSegPtr, destSegPtr);
  1564.     VmDecPTUserCount(srcSegPtr);
  1565.  
  1566.     /*
  1567.      * If couldn't copy the swap space over then return an error.
  1568.      */
  1569.     if (status != SUCCESS) {
  1570.     Vm_SegmentDelete(destSegPtr, procPtr);
  1571.     return(VM_SWAP_ERROR);
  1572.     }
  1573.  
  1574.     *destSegPtrPtr = destSegPtr;
  1575.  
  1576.     return(SUCCESS);
  1577. }
  1578.  
  1579.  
  1580. /*
  1581.  * ----------------------------------------------------------------------------
  1582.  *
  1583.  * IncPTUserCount --
  1584.  *
  1585.  *         Increment the count of users of the page tables for the given segment.
  1586.  *
  1587.  * Results:
  1588.  *     None.
  1589.  *
  1590.  * Side effects:
  1591.  *     Count of users of page table incremented.
  1592.  *     
  1593.  * ----------------------------------------------------------------------------
  1594.  */
  1595. ENTRY static void
  1596. IncPTUserCount(segPtr)
  1597.     register    Vm_Segment    *segPtr;
  1598. {
  1599.     LOCK_MONITOR;
  1600.  
  1601.     while (segPtr->flags & VM_PT_EXCL_ACC) {
  1602.     (void)Sync_Wait(&segPtr->condition, FALSE);
  1603.     }
  1604.     segPtr->ptUserCount++;
  1605.  
  1606.     UNLOCK_MONITOR;
  1607. }
  1608.  
  1609. /*
  1610.  * ----------------------------------------------------------------------------
  1611.  *
  1612.  * The following routines, VmSegCanCOW, VmSegCantCOW and VmSegCOWDone,
  1613.  * synchronize the marking of a segment as non-copy-on-writeable (i.e. it
  1614.  * has to be copied at fork time). The routines that wire pages into a
  1615.  * user's address space can't allow pages that they have wired down to all
  1616.  * of a sudden become copy-on-write because this can cause page faults
  1617.  * at bad times (e.g. with interrupts disabled).  Thus before they wire
  1618.  * pages down they make sure that the segment that the pages reside in
  1619.  * cannot be made copy-on-write.  They do this by calling the routine
  1620.  * VmSegCantCOW.  The routine above (Vm_SegmentDup) wants to decide if it
  1621.  * should duplicate the segment with COW or with copy-on-fork.  It decides
  1622.  * what to do by calling the routine VmSegCanCOW which will return TRUE
  1623.  * if the segment can be copied copy-on-write and will prevent the routine
  1624.  * VmSegCantCOW from doing its thing.  Once a segment has been successfully
  1625.  * duplicated with COW then the routine VmSegCOWDone is called which allows
  1626.  * VmSegCantCOW to proceed.
  1627.  */
  1628.  
  1629. /*
  1630.  * ----------------------------------------------------------------------------
  1631.  *
  1632.  * VmSegCanCOW --
  1633.  *
  1634.  *         Return TRUE if can fork this segment copy-on-write.  If the 
  1635.  *    VM_SEG_COW_IN_PROGRESS flag is set then wait until its cleared
  1636.  *    before making the decision about whether this segment can
  1637.  *    be forked copy-on-write. 
  1638.  *
  1639.  * Results:
  1640.  *    TRUE if can fork this segment copy-on-write.
  1641.  *
  1642.  * Side effects:
  1643.  *    VM_SEG_COW_IN_PROGRESS flag set if the can be made copy-on-write.
  1644.  *     
  1645.  * ----------------------------------------------------------------------------
  1646.  */
  1647. ENTRY Boolean
  1648. VmSegCanCOW(segPtr)
  1649.     Vm_Segment    *segPtr;
  1650. {
  1651.     Boolean    retVal;
  1652.  
  1653.     LOCK_MONITOR;
  1654.  
  1655.     while (segPtr->flags & VM_SEG_COW_IN_PROGRESS) {
  1656.     (void)Sync_Wait(&segPtr->condition, FALSE);
  1657.     }
  1658.     if (segPtr->flags & VM_SEG_CANT_COW) {
  1659.     retVal = FALSE;
  1660.     } else {
  1661.     retVal = TRUE;
  1662.     segPtr->flags |= VM_SEG_COW_IN_PROGRESS;
  1663.     }
  1664.  
  1665.     UNLOCK_MONITOR;
  1666.  
  1667.     return(retVal);
  1668. }
  1669.  
  1670.  
  1671.  
  1672. /*
  1673.  * ----------------------------------------------------------------------------
  1674.  *
  1675.  * VmSegCantCOW --
  1676.  *
  1677.  *         Mark this segment such that it can no longer be made copy-on-write.
  1678.  *
  1679.  * Results:
  1680.  *    None.
  1681.  *
  1682.  * Side effects:
  1683.  *    VM_SEG_CANT_COW flag set.
  1684.  *     
  1685.  * ----------------------------------------------------------------------------
  1686.  */
  1687. void
  1688. VmSegCantCOW(segPtr)
  1689.     Vm_Segment    *segPtr;
  1690. {
  1691.     if (!VmSegCanCOW(segPtr)) {
  1692.     return;
  1693.     }
  1694.     (void)VmCOWCopySeg(segPtr);
  1695.     VmSegCOWDone(segPtr, TRUE);
  1696. }
  1697.  
  1698.  
  1699. /*
  1700.  * ----------------------------------------------------------------------------
  1701.  *
  1702.  * VmSegCOWDone --
  1703.  *
  1704.  *         A copy-on-fork operation has completed.
  1705.  *
  1706.  * Results:
  1707.  *    None.
  1708.  *
  1709.  * Side effects:
  1710.  *    VM_SEG_COW_IN_PROGRESS flag cleared.
  1711.  *     
  1712.  * ----------------------------------------------------------------------------
  1713.  */
  1714. ENTRY void
  1715. VmSegCOWDone(segPtr, cantCOW)
  1716.     Vm_Segment    *segPtr;
  1717.     Boolean    cantCOW;
  1718. {
  1719.     LOCK_MONITOR;
  1720.  
  1721.     if (cantCOW) {
  1722.     segPtr->flags |= VM_SEG_CANT_COW;
  1723.     }
  1724.     segPtr->flags &= ~VM_SEG_COW_IN_PROGRESS;
  1725.     Sync_Broadcast(&segPtr->condition);
  1726.  
  1727.     UNLOCK_MONITOR;
  1728. }
  1729.  
  1730.  
  1731. /*
  1732.  *----------------------------------------------------------------------
  1733.  *
  1734.  * CopyInfo --
  1735.  *
  1736.  *    Copy over pertinent information in the source including page
  1737.  *    tables to the destination segment.
  1738.  *
  1739.  * Results:
  1740.  *    None.
  1741.  *
  1742.  * Side effects:
  1743.  *    Page table and virtual address pointers set for source and destination
  1744.  *    segments.
  1745.  *
  1746.  *----------------------------------------------------------------------
  1747.  */
  1748. ENTRY static void
  1749. CopyInfo(srcSegPtr, destSegPtr, srcPTEPtrPtr, destPTEPtrPtr, 
  1750.      srcVirtAddrPtr, destVirtAddrPtr)
  1751.     register    Vm_Segment    *srcSegPtr;
  1752.     register    Vm_Segment    *destSegPtr;
  1753.     register    Vm_PTE        **srcPTEPtrPtr;
  1754.     register    Vm_PTE        **destPTEPtrPtr;
  1755.     Vm_VirtAddr            *srcVirtAddrPtr;
  1756.     Vm_VirtAddr            *destVirtAddrPtr;
  1757. {
  1758.     LOCK_MONITOR;
  1759.  
  1760.     if (srcSegPtr->type == VM_HEAP) {
  1761.     *srcPTEPtrPtr = srcSegPtr->ptPtr;
  1762.     *destPTEPtrPtr = destSegPtr->ptPtr;
  1763.     destVirtAddrPtr->page = srcSegPtr->offset;
  1764.     } else {
  1765.     destVirtAddrPtr->page = mach_LastUserStackPage - 
  1766.                         srcSegPtr->numPages + 1;
  1767.     *srcPTEPtrPtr = VmGetPTEPtr(srcSegPtr, destVirtAddrPtr->page);
  1768.     *destPTEPtrPtr = VmGetPTEPtr(destSegPtr, destVirtAddrPtr->page);
  1769.     }
  1770.     destVirtAddrPtr->segPtr = destSegPtr;
  1771.     srcVirtAddrPtr->segPtr = srcSegPtr;
  1772.     srcVirtAddrPtr->page = destVirtAddrPtr->page;
  1773.     srcVirtAddrPtr->sharedPtr = (Vm_SegProcList *)NIL;
  1774.     destVirtAddrPtr->sharedPtr = (Vm_SegProcList *)NIL;
  1775.  
  1776.     UNLOCK_MONITOR;
  1777. }
  1778.  
  1779.  
  1780. /*
  1781.  *----------------------------------------------------------------------
  1782.  *
  1783.  * CopyPage --
  1784.  *
  1785.  *    Determine if the page in the source segment needs to be duplicated.
  1786.  *    If the page is to be duplicated then return the source page frame
  1787.  *    locked and return TRUE.  Otherwise return FALSE.
  1788.  *
  1789.  * Results:
  1790.  *    TRUE if page needs to be duplicated, FALSE if not.
  1791.  *
  1792.  * Side effects:
  1793.  *    Source page frame may be locked.
  1794.  *
  1795.  *----------------------------------------------------------------------
  1796.  */
  1797. ENTRY static Boolean
  1798. CopyPage(srcSegPtr, srcPTEPtr, destPTEPtr)
  1799.     Vm_Segment            *srcSegPtr;
  1800.     register    Vm_PTE        *srcPTEPtr;
  1801.     register    Vm_PTE        *destPTEPtr;
  1802. {
  1803.     Boolean    residentPage;
  1804.  
  1805.     LOCK_MONITOR;
  1806.  
  1807.     while (*srcPTEPtr & VM_IN_PROGRESS_BIT) {
  1808.     (void)Sync_Wait(&srcSegPtr->condition, FALSE);
  1809.     }
  1810.     residentPage = *srcPTEPtr & VM_PHYS_RES_BIT;
  1811.     *destPTEPtr = *srcPTEPtr;
  1812.     if (residentPage) {
  1813.     /*
  1814.      * Copy over all resident pages.  Can reload swapped pages but its a 
  1815.      * lot cheaper to do a memory-to-memory copy than send an RPC to the
  1816.      * server to copy the page on swap space.  
  1817.      */
  1818.     VmLockPageInt(Vm_GetPageFrame(*srcPTEPtr));
  1819.     *destPTEPtr &= ~(VM_ON_SWAP_BIT | VM_PAGE_FRAME_FIELD);
  1820.     } else {
  1821.     *destPTEPtr &= ~VM_PAGE_FRAME_FIELD;
  1822.     /* 
  1823.      * This page is on the swap file but not in memory so we are
  1824.      * going to have to copy over the swap space for this page.
  1825.      * Use the in-progress bit to mark this fact.
  1826.      */
  1827.     if (*destPTEPtr & VM_ON_SWAP_BIT) {
  1828.         *destPTEPtr |= VM_IN_PROGRESS_BIT;
  1829.     }
  1830.     }
  1831.  
  1832.     UNLOCK_MONITOR;
  1833.  
  1834.     return(residentPage);
  1835. }
  1836.  
  1837.  
  1838. /*
  1839.  *----------------------------------------------------------------------
  1840.  *
  1841.  * SegmentIncRef --
  1842.  *
  1843.  *    Increment the reference count for the given segment and put it into
  1844.  *    the list of processes sharing this segment.
  1845.  *
  1846.  * Results:
  1847.  *    None.
  1848.  *
  1849.  * Side effects:
  1850.  *    The given segment in the segment table is modified.
  1851.  *
  1852.  *----------------------------------------------------------------------
  1853.  */
  1854. ENTRY static void
  1855. SegmentIncRef(segPtr, procLinkPtr) 
  1856.     register    Vm_Segment    *segPtr;
  1857.     register    VmProcLink    *procLinkPtr;
  1858. {
  1859.     LOCK_MONITOR;
  1860.  
  1861.     segPtr->refCount++;
  1862.  
  1863.     /*
  1864.      * Put the process into the list of processes sharing this segment.
  1865.      */
  1866.     List_Insert((List_Links *) procLinkPtr, LIST_ATFRONT(segPtr->procList));
  1867.  
  1868.     UNLOCK_MONITOR;
  1869. }
  1870.  
  1871.  
  1872. /*
  1873.  *----------------------------------------------------------------------
  1874.  *
  1875.  * Vm_SegmentIncRef --
  1876.  *
  1877.  *    Increment the reference count for the given segment and put it into
  1878.  *    the list of processes sharing this segment.
  1879.  *
  1880.  * Results:
  1881.  *    None.
  1882.  *
  1883.  * Side effects:
  1884.  *    The given segment in the segment table is modified.
  1885.  *
  1886.  *----------------------------------------------------------------------
  1887.  */
  1888. void
  1889. Vm_SegmentIncRef(segPtr, procPtr) 
  1890.     Vm_Segment        *segPtr;
  1891.     Proc_ControlBlock    *procPtr;
  1892. {
  1893.     register    VmProcLink    *procLinkPtr;
  1894.  
  1895.     procLinkPtr = (VmProcLink *) malloc(sizeof(VmProcLink));
  1896.     procLinkPtr->procPtr = procPtr;
  1897.  
  1898.     SegmentIncRef(segPtr, procLinkPtr);
  1899. }
  1900.  
  1901.  
  1902. /*
  1903.  *----------------------------------------------------------------------
  1904.  *
  1905.  * Vm_GetSegInfo --
  1906.  *
  1907.  *
  1908.  *    This routine takes in a pointer to a proc table entry and returns
  1909.  *    the segment table information for the segments that it uses.
  1910.  *    If the proc table entry corresponds to a migrated process,
  1911.  *     contact its current host.
  1912.  *
  1913.  * Results:
  1914.  *    SUCCESS if could get the information, SYS_ARG_NOACCESS if the
  1915.  *    the pointer to the segment table entries passed in are bad amd
  1916.  *    SYS_INVALID_ARG if one of the segment pointers in the proc table
  1917.  *    are bad.  Or, the result from the RPC to get the migrated process's
  1918.  *    info.
  1919.  *
  1920.  * Side effects:
  1921.  *    None.
  1922.  *
  1923.  *----------------------------------------------------------------------
  1924.  */
  1925.  
  1926. ReturnStatus
  1927. Vm_GetSegInfo(infoPtr, segID, infoSize, segBufPtr)
  1928.     Proc_PCBInfo    *infoPtr;    /* User's copy of PCB.  Contains
  1929.                      * pointers to segment structures.
  1930.                      * USER_NIL => Want to use a 
  1931.                      *     specific segment number. */
  1932.     Vm_SegmentID    segID;        /* Segment number of get info for.  
  1933.                      * Ignored unless previous argument
  1934.                      * is USER_NIL. */
  1935.     int            infoSize;    /* Size of segment info structures */
  1936.     Address        segBufPtr;    /* Where to store segment information.*/
  1937. {
  1938.     Proc_PCBInfo    pcbInfo;
  1939.     Vm_Segment        *minSegAddr, *maxSegAddr, *segPtr;
  1940.     int            i;
  1941.     int            segNum;
  1942.     int            bytesToCopy;
  1943.     Vm_SegmentInfo    segmentInfo;
  1944.     int            host;
  1945.     Proc_ControlBlock    *procPtr;
  1946.     ReturnStatus     status;
  1947.  
  1948.     segNum = (int) segID;
  1949.     bytesToCopy = min(sizeof(Vm_SegmentInfo), infoSize);
  1950.     minSegAddr = segmentTable;
  1951.     maxSegAddr = &(segmentTable[vmNumSegments - 1]);
  1952.     if (infoPtr != (Proc_PCBInfo *)USER_NIL) {
  1953.     if (Vm_CopyIn(sizeof(pcbInfo), (Address) infoPtr,
  1954.               (Address) &pcbInfo) != SUCCESS) {
  1955.         return(SYS_ARG_NOACCESS);
  1956.     }
  1957.     /*
  1958.      * Follow remote processes.  Use the peerHostID as a hint.
  1959.      */
  1960.     host = 0;
  1961.     if (pcbInfo.peerHostID != (int) NIL) {
  1962.         procPtr = Proc_LockPID(pcbInfo.processID);
  1963.         if (procPtr != (Proc_ControlBlock *) NIL) {
  1964.         if (procPtr->state == PROC_MIGRATED) {
  1965.             host = procPtr->peerHostID;
  1966.         }
  1967.         Proc_Unlock(procPtr);
  1968.         }
  1969.     }
  1970.     for (i = VM_CODE; i <= VM_STACK; i++, segBufPtr += infoSize) {
  1971.         if (pcbInfo.genFlags & PROC_KERNEL) {
  1972.         segPtr = vm_SysSegPtr;
  1973.         FillSegmentInfo(segPtr, &segmentInfo);
  1974.         } else {
  1975.         segNum = pcbInfo.vmSegments[i];
  1976.         if (segNum < 0 || segNum >= vmNumSegments) {
  1977.             return(SYS_INVALID_ARG);
  1978.         }
  1979.         if (host) {
  1980.             status = Proc_GetRemoteSegInfo(host, segNum, &segmentInfo);
  1981.             if (status != SUCCESS) {
  1982.             return(status);
  1983.             }
  1984.         } else {
  1985.             segPtr = &segmentTable[segNum];
  1986.             if (segPtr < minSegAddr || segPtr > maxSegAddr) {
  1987.             return(SYS_INVALID_ARG);
  1988.             }
  1989.             FillSegmentInfo(segPtr, &segmentInfo);
  1990.         }
  1991.         }
  1992.         if (Vm_CopyOut(bytesToCopy, (Address) &segmentInfo, 
  1993.                segBufPtr) != SUCCESS) { 
  1994.         return(SYS_ARG_NOACCESS);
  1995.         }
  1996.     }
  1997.     } else if (segNum < 0 || segNum >= vmNumSegments) {
  1998.     return(SYS_INVALID_ARG);
  1999.     } else {
  2000.     segPtr = &segmentTable[segNum];
  2001.     if (segPtr < minSegAddr || segPtr > maxSegAddr) {
  2002.         return(SYS_INVALID_ARG);
  2003.     }
  2004.     FillSegmentInfo(segPtr, &segmentInfo);
  2005.     if (Vm_CopyOut(bytesToCopy, (Address) &segmentInfo, 
  2006.                segBufPtr) != SUCCESS) { 
  2007.         return(SYS_ARG_NOACCESS);
  2008.     }
  2009.     }
  2010.  
  2011.     return(SUCCESS);
  2012. }
  2013.  
  2014. /*
  2015.  *----------------------------------------------------------------------
  2016.  *
  2017.  * FillSegmentInfo --
  2018.  *
  2019.  *    Converts the contents of a Vm_Segment to a Vm_SegmentInfo.
  2020.  *    This allows the kernel definition of Vm_Segment to change without
  2021.  *    affecting user programs.
  2022.  *
  2023.  * Results:
  2024.  *    None.
  2025.  *
  2026.  * Side effects:
  2027.  *    None.
  2028.  *
  2029.  *----------------------------------------------------------------------
  2030.  */
  2031.  
  2032. static void
  2033. FillSegmentInfo(segPtr, infoPtr)
  2034.     Vm_Segment        *segPtr;    /* Segment to convert */
  2035.     Vm_SegmentInfo    *infoPtr;    /* Conversion result */
  2036. {
  2037.     infoPtr->segNum = segPtr->segNum;
  2038.     infoPtr->refCount = segPtr->refCount;
  2039.     infoPtr->type = segPtr->type;
  2040.     if (infoPtr->type == VM_CODE) {
  2041.     (void)strncpy(infoPtr->objFileName, segPtr->objFileName,
  2042.             VM_OBJ_FILE_NAME_LENGTH);
  2043.     infoPtr->objFileName[VM_OBJ_FILE_NAME_LENGTH -1] = '\0';
  2044.     } else {
  2045.     infoPtr->objFileName[0] = '\0';
  2046.     }
  2047.     infoPtr->numPages = segPtr->numPages;
  2048.     infoPtr->ptSize = segPtr->ptSize;
  2049.     infoPtr->resPages = segPtr->resPages;
  2050.     infoPtr->flags = segPtr->flags;
  2051.     infoPtr->ptUserCount = segPtr->ptUserCount;
  2052.     infoPtr->numCOWPages = segPtr->numCOWPages;
  2053.     infoPtr->numCORPages = segPtr->numCORPages;
  2054.     infoPtr->minAddr = segPtr->minAddr;
  2055.     infoPtr->maxAddr = segPtr->maxAddr;
  2056.     infoPtr->traceTime = segPtr->traceTime;
  2057. }
  2058.  
  2059.  
  2060. /*
  2061.  *----------------------------------------------------------------------
  2062.  *
  2063.  * VmGetSegPtr --
  2064.  *
  2065.  *    Return a pointer to the given segment.
  2066.  *
  2067.  * Results:
  2068.  *    Pointer to given segment.
  2069.  *
  2070.  * Side effects:
  2071.  *    None.
  2072.  *
  2073.  *----------------------------------------------------------------------
  2074.  */
  2075. Vm_Segment *
  2076. VmGetSegPtr(segNum)
  2077.     int    segNum;
  2078. {
  2079.     return(&segmentTable[segNum]);
  2080. }
  2081.  
  2082.  
  2083. /*
  2084.  *----------------------------------------------------------------------
  2085.  *
  2086.  * Vm_EncapSegInfo --
  2087.  *
  2088.  *    Encapsulate information for a particular segment.  This is used
  2089.  *     to send info to other hosts (for ps, e.g.).
  2090.  *
  2091.  * Results:
  2092.  *    SUCCESS, or invalid arg if the segment doesn't exist.
  2093.  *
  2094.  * Side effects:
  2095.  *    None.
  2096.  *
  2097.  *----------------------------------------------------------------------
  2098.  */
  2099. ReturnStatus
  2100. Vm_EncapSegInfo(segNum, infoPtr)
  2101.     int    segNum;            /* Number of the segment. */
  2102.     Vm_SegmentInfo *infoPtr;    /* Pointer to encapsulated data. */
  2103. {
  2104.     Vm_Segment *segPtr;
  2105.     segPtr = &segmentTable[segNum];
  2106.     if (segPtr < segmentTable ||
  2107.     segPtr > &(segmentTable[vmNumSegments - 1])) {
  2108.     return(GEN_INVALID_ARG);
  2109.     }
  2110.     FillSegmentInfo(segPtr, infoPtr);
  2111.     return(SUCCESS);
  2112. }
  2113.  
  2114.  
  2115.  
  2116. /*
  2117.  * ----------------------------------------------------------------------------
  2118.  *
  2119.  * VmTraceSegStart --
  2120.  *
  2121.  *    Reset all segment trace times and dump a creation record for
  2122.  *    each in-use segment.
  2123.  *
  2124.  * Results:
  2125.  *    None.
  2126.  *
  2127.  * Side effects:
  2128.  *    All segment trace times are set to 0.
  2129.  *     
  2130.  * ----------------------------------------------------------------------------
  2131.  */
  2132. INTERNAL void
  2133. VmTraceSegStart()
  2134. {
  2135.     int        i;
  2136.     Vm_Segment    *segPtr;
  2137.  
  2138.     for (i = 0, segPtr = segmentTable; i < vmNumSegments; i++, segPtr++) {
  2139.     if (i != VM_SYSTEM_SEGMENT) {
  2140.         segPtr->traceTime = 0;
  2141.         if (segPtr->refCount > 0 ||
  2142.             (segPtr->flags & VM_SEG_INACTIVE)) {
  2143.         Vm_TraceSegCreate    segCreate;
  2144.     
  2145.         segCreate.segNum = segPtr->segNum;
  2146.         segCreate.parSegNum = -1;
  2147.         segCreate.segType = segPtr->type;
  2148.         segCreate.cor = segPtr->numCORPages > 0;
  2149.         VmStoreTraceRec(VM_TRACE_SEG_CREATE_REC, sizeof(segCreate),
  2150.                 (Address)&segCreate, TRUE);
  2151.         segPtr->flags |= VM_SEG_CREATE_TRACED;
  2152.         }
  2153.     }
  2154.     }
  2155. }
  2156.